package com.example.flowable.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.annotations.*;
import com.example.db.TableService;
import com.example.flowable.FLowableUtils;
import com.example.flowable.config.ExpressionCmd;
import com.example.utils.Results;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.*;
import org.flowable.engine.*;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Classname NodeController
 * @Description TODO
 * @Date 2022/8/14 18:44
 * @Created by XiongXiong
 * @Author: X.I.O
 */
@Auth
@RestController("/node")
public class NodeController {

    @Autowired
    FLowableUtils fLowableUtils;

    @GetMapping(value = "/getallnode",desc = "获取所有节点")
    public JSONObject getAllNodeController(@Param("processId")String processId){
        Map<String,Object> map=new HashMap<>();
        List<FlowElement> elements=calApprovePath(processId, map);
        JSONArray jsonArray = new JSONArray();
        JSONObject obj = null;
        for (FlowElement ele : elements) {
            obj=new JSONObject();
            obj.put("id",ele.getId());
            obj.put("name",ele.getName());
            jsonArray.add(obj);
        }
        return Results.success(jsonArray);
    }

    @GetMapping(value = "/getnextnode",desc = "获取下一节点信息")
    public JSONObject getNextNodeController(@Param("processId")String processId){
        TaskService taskService =fLowableUtils.getTaskService();
        List<Task> tasks=taskService.createTaskQuery().processInstanceId(processId).list();
        if(tasks==null && tasks.size() == 0){
            return Results.error("任务信息为null");
        }
        Task task=tasks.get(0);
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery()
                .executionId(task.getExecutionId()).singleResult();
        // 当前审批节点
        String crruentActivityId = ee.getActivityId();
        RepositoryService repositoryService=fLowableUtils.getRepositoryService();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        // 输出连线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
        JSONArray array=new JSONArray();
        for (SequenceFlow seq : outFlows) {
            //当前审批节点
            FlowElement sourceFlowElement = seq.getSourceFlowElement();
            JSONObject obj=new JSONObject();
            obj.put("now","当前节点："+sourceFlowElement.getId() +" 节点名称： "+sourceFlowElement.getName());
            // 下一个审批节点
            FlowElement targetFlow = seq.getTargetFlowElement();
            if (targetFlow instanceof UserTask) {
                obj.put("next","下一节点："+targetFlow.getId() +" 节点名称： "+targetFlow.getName());
            }
            // 如果下个审批节点为结束节点
            if (targetFlow instanceof EndEvent) {
                obj.put("end","下一节点："+targetFlow.getId() +" 节点名称： "+targetFlow.getName());
            }
            if(targetFlow instanceof ExclusiveGateway){
                dealGetWay(targetFlow,new HashMap());
                obj.put("getway","下一节点: "+targetFlow.getId() + "节点名称: "+targetFlow.getName()+" ");
            }
            array.add(obj);
        }
        return Results.success(array);
    }


    private void dealGetWay(FlowElement flowElement,Map data) {
        List<SequenceFlow> targetFlows=((ExclusiveGateway)flowElement).getOutgoingFlows();
        // 循环每个网关分支
        for(SequenceFlow sequenceFlow : targetFlows) {
            // 获取下一个网关和节点数据
            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
            // 网关数据不为空
            if (sequenceFlow.getConditionExpression() != null && !"".equals(sequenceFlow.getConditionExpression())) {
                //计算连接线上的表达式
                //  Object result = managementService.executeCommand(new ExpressionEvaluateUtil(sequenceFlow.getConditionExpression(), data));
                System.out.println("排他网关中线条: id=" + sequenceFlow.getId() + ",name=" + sequenceFlow.getName() + ",result=,ConditionExpression=" + sequenceFlow.getConditionExpression());
                // 获取网关判断条件
                String conditionExpression = null;
                if (sequenceFlow.getConditionExpression() != null) {
                    conditionExpression = sequenceFlow.getConditionExpression().substring(sequenceFlow.getConditionExpression().indexOf("==") + 2,
                            sequenceFlow.getConditionExpression().indexOf("}"));
                }
                System.out.println("截取后的选择条件: id=" + conditionExpression);
            }
            // 网关的下个节点是用户节点
            if (targetFlowElement instanceof UserTask) {
                // 判断是否是会签
                UserTask userTask = (UserTask) targetFlowElement;
                if (userTask.getBehavior() instanceof ParallelMultiInstanceBehavior) {
                    ParallelMultiInstanceBehavior behavior = (ParallelMultiInstanceBehavior) userTask.getBehavior();
                    if (behavior != null && behavior.getCollectionExpression() != null) {
                        System.out.println("当前节点是会签");
                    }
                } else {
                    System.out.println("当前节点不是会签");
                }
                System.out.println("排他网关的下一节点是UserTask: id=" + targetFlowElement.getId() + ",name=" + targetFlowElement.getName());
                System.out.println("排他网关的下一节点CandidateUsers候选者" + ((UserTask) targetFlowElement).getCandidateUsers());

            } else if (targetFlowElement instanceof EndEvent) {
                System.out.println("排他网关的下一节点是EndEvent: 结束节点");
            } else if (targetFlowElement instanceof ServiceTask) {
                System.out.println("排他网关的下一节点是ServiceTask: 内部方法");
            } else if (targetFlowElement instanceof ExclusiveGateway) {
                //  setExclusiveGateway(targetFlowElement,data);
            } else if (targetFlowElement instanceof SubProcess) {
                System.out.println("排他网关的下一节点是SubProcess: 内部子流程");
            }
        }
    }

    /**
     * 1. 首先拿到BpmnModel，所有流程定义信息都可以通过BpmnModel获取；若流程尚未发起，则用modelId查询最新部署的流程定义数据；
     * 若流程已经发起，可以通过流程实例的processDefinitionId查询流程定义的历史数据。
     * @param variableMap 流程变量，用于计算条件分支
     */
    private List<FlowElement> calApprovePath(String processInstanceId, Map<String, Object> variableMap){
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        RepositoryService repositoryService=fLowableUtils.getRepositoryService();
        BpmnModel bpmnModel=null;
        if(StringUtils.isNotBlank(processInstanceId)){
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        }
        if(bpmnModel==null){
            return Collections.emptyList();
        }
        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
        System.out.println(flowElements.size()+"size ==>");
        for (FlowElement flowElement : flowElements) {
            System.out.println(flowElement.getName());
            System.out.println(flowElement.getId());
        }
        List<FlowElement> passElements = new ArrayList<>();
        this.dueStartElement(passElements, flowElements, variableMap);
        return passElements;
    }

    private void dueUserTaskElement(List<FlowElement> passElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap){
        passElements.add(curFlowElement);
        List<SequenceFlow> outgoingFlows = ((UserTask) curFlowElement).getOutgoingFlows();
        String targetRef = outgoingFlows.get(0).getTargetRef();
        if (outgoingFlows.size() > 1) {
            // 找到表达式成立的sequenceFlow
            SequenceFlow sequenceFlow = getSequenceFlow(variableMap, outgoingFlows);
            targetRef = sequenceFlow.getTargetRef();
        }
        // 根据ID找到FlowElement
        FlowElement targetElement = getFlowElement(flowElements, targetRef);
        this.getPassElementList(passElements, flowElements, targetElement, variableMap);
    }



    private void dueExclusiveGateway(List<FlowElement> passElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap){
        // 获取符合条件的sequenceFlow的目标FlowElement
        List<SequenceFlow> exclusiveGatewayOutgoingFlows = ((ExclusiveGateway) curFlowElement).getOutgoingFlows();
        flowElements.remove(curFlowElement);
        // 找到表达式成立的sequenceFlow
        SequenceFlow sequenceFlow = getSequenceFlow(variableMap, exclusiveGatewayOutgoingFlows);
        // 根据ID找到FlowElement
        FlowElement targetElement = getFlowElement(flowElements, sequenceFlow.getTargetRef());
        this.getPassElementList(passElements, flowElements, targetElement, variableMap);
    }

    private void dueParallelGateway(List<FlowElement> passElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap){
        FlowElement targetElement;
        List<SequenceFlow> parallelGatewayOutgoingFlows = ((ParallelGateway) curFlowElement).getOutgoingFlows();
        for(SequenceFlow sequenceFlow : parallelGatewayOutgoingFlows){
            targetElement = getFlowElement(flowElements, sequenceFlow.getTargetRef());
            this.getPassElementList(passElements, flowElements, targetElement, variableMap);
        }
    }



    /**
     * 3. 我只用到了UserTask、ExclusiveGateway、ParallelGateway，所以代码里只列举了这三种，如果用到了其他的，可以再自己补充
     */
    private void getPassElementList(List<FlowElement> passElements, Collection<FlowElement> flowElements, FlowElement curFlowElement, Map<String, Object> variableMap){
        // 任务节点
        if (curFlowElement instanceof UserTask) {
            this.dueUserTaskElement(passElements, flowElements, curFlowElement, variableMap);
            return;
        }
        // 排他网关
        if (curFlowElement instanceof ExclusiveGateway) {
            this.dueExclusiveGateway(passElements, flowElements, curFlowElement, variableMap);
            return;
        }
        // 并行网关
        if(curFlowElement instanceof ParallelGateway){
            this.dueParallelGateway(passElements, flowElements, curFlowElement, variableMap);
        }
    }



    /**
     * 4. 根据传入的变量，计算出表达式成立的那一条SequenceFlow
     * @param variableMap
     * @param outgoingFlows
     * @return
     */
    private SequenceFlow getSequenceFlow(Map<String, Object> variableMap, List<SequenceFlow> outgoingFlows) {
        Optional<SequenceFlow> sequenceFlowOpt = outgoingFlows.stream().filter(item -> {
            try {
                return this.getElValue(item.getConditionExpression(), variableMap);
            } catch (Exception e) {
                System.out.println(e.getMessage()+"异常");
                return false;
            }
        }).findFirst();
        return sequenceFlowOpt.orElse(outgoingFlows.get(0));
    }

    /**
     * 2. 找到开始节点，通过它的目标节点，然后再不断往下找。
     */
    private void dueStartElement(List<FlowElement> passElements, Collection<FlowElement> flowElements, Map<String, Object> variableMap){
        Optional<FlowElement> startElementOpt = flowElements.stream().filter(flowElement -> flowElement instanceof StartEvent).findFirst();
        startElementOpt.ifPresent(startElement -> {
            flowElements.remove(startElement);
            List<SequenceFlow> outgoingFlows = ((StartEvent) startElement).getOutgoingFlows();
            String targetRef = outgoingFlows.get(0).getTargetRef();
            // 根据ID找到FlowElement
            FlowElement targetElementOfStartElement = getFlowElement(flowElements, targetRef);
            if (targetElementOfStartElement instanceof UserTask) {
                this.getPassElementList(passElements, flowElements, targetElementOfStartElement, variableMap);
            }
        });
    }


    /***
     * 根据ID找到FlowElement
     * @param flowElements
     * @param targetRef
     * @return
     */
    private FlowElement getFlowElement(Collection<FlowElement> flowElements, String targetRef) {
        List<FlowElement> targetFlowElements = flowElements.stream().filter(
                flowElement -> !StringUtils.isEmpty(flowElement.getId()) && flowElement.getId().equals(targetRef)
        ).collect(Collectors.toList());
        if (targetFlowElements.size() > 0) {
            return targetFlowElements.get(0);
        }
        return null;
    }



    private boolean getElValue(String exp, Map<String, Object> variableMap){
        ManagementService managementService=fLowableUtils.getProcessEngine().getManagementService();
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        fLowableUtils.getProcessEngine().getProcessEngineConfiguration();

        ProcessEngineConfigurationImpl processEngineConfiguration=(ProcessEngineConfigurationImpl)fLowableUtils.getProcessEngine().getProcessEngineConfiguration();
        return managementService.executeCommand(new ExpressionCmd(
                runtimeService, processEngineConfiguration, null, exp, variableMap));
    }

}
